# coding = utf-8

import sys

from PySide6.QtWidgets import (QApplication,QMainWindow,QWidget,QStatusBar,QPlainTextEdit,
                               QVBoxLayout,QLabel,QFrame,QFileDialog,QFontDialog,QMessageBox)
from PySide6.QtGui import QGuiApplication,QKeySequence,QPixmap,QDesktopServices
from PySide6.QtCore import QDateTime
from PySide6.QtPrintSupport import QPrintDialog,QPrinter
from CustomModule.findDialog import QFindTextDialog
from pathlib import Path

class MainNotePad(QMainWindow):
    def __init__(self):
        super().__init__()
        self.homePath = str(Path.home())
        self.filePath = None

        self.setupUi()
        self.eventHand()

        # 添加一些属性 记录查找窗口的变量
        self.lineEditText = None
        
    def setupUi(self):
        self.setWindowTitle("无标题 - 记事本")
        self.resize(862, 561)
        self.menuBar_ = self.menuBar()
        self.setFileMenu()
        self.setEditMenu()
        self.setFormatMenu()
        self.setViewMenu()
        self.setHelpMenu()
        self.setPlainText()
        self.setMyStatusBar()
        
    def setFileMenu(self):
        """
        文件菜单 子行为 以及快捷方式
        """
        # 添加文件菜单及其子行为
        fileMenuBar = self.menuBar_.addMenu("文件(&F)")
        
        self.newFile_ = fileMenuBar.addAction("新建(&N)")
        self.newWindow_ = fileMenuBar.addAction("新窗口(&W)")
        self.openFile_ = fileMenuBar.addAction("打开(&O)")
        self.saveFile_ = fileMenuBar.addAction("保存(&S)")
        fileMenuBar.addSeparator()
        self.saveFileAs_ = fileMenuBar.addAction("另存为(&A)")
        setUi =  fileMenuBar.addAction("界面设置(&U)")
        self.printFile = fileMenuBar.addAction("打印(&P)")
        fileMenuBar.addSeparator()
        self.exit_ = fileMenuBar.addAction("退出(&X)")

        # 添加快捷方式   
        ## 规范快捷键设置 https://doc.qt.io/qtforpython-6/PySide6/QtGui/QKeySequence.html#standard-shortcuts
        self.newFile_.setShortcut(QKeySequence.StandardKey.New)
        self.newWindow_.setShortcut("Ctrl+Shift+N")
        self.openFile_.setShortcut(QKeySequence.StandardKey.Open)
        self.saveFile_.setShortcut(QKeySequence.StandardKey.Save)
        self.saveFileAs_.setShortcut(QKeySequence.StandardKey.SaveAs)
        self.printFile.setShortcut(QKeySequence.StandardKey.Print)
        self.exit_.setShortcut(QKeySequence.StandardKey.Close) # 不添加在Gnome上无法关闭窗口

        # 添加行为到子菜单中
        # addAction() https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QWidget.html#PySide6.QtWidgets.QWidget.addAction
        # addActions() https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QWidget.html#PySide6.QtWidgets.QWidget.addActions

    def setEditMenu(self):
        """
       编辑菜单 子行为以及快捷方式
       行为是否可用
       替换 全选 时间 默认可用
        """
        editMenu = self.menuBar_.addMenu("编辑(&E)")

        undo = editMenu.addAction("撤销(&U)")
        editMenu.addSeparator()
        cut =  editMenu.addAction("剪切(&T)")
        copy = editMenu.addAction("复制(&C)")
        self.paste = editMenu.addAction("粘贴(&P)")
        delete =  editMenu.addAction("删除(&L)")
        editMenu.addSeparator()
        self.search =  editMenu.addAction("使用Bing搜索") # 默认浏览器使用Bing搜索
        self.find_ =  editMenu.addAction("查找(&F)")
        self.findNext = editMenu.addAction("查找下一个(&N)")
        self.findPrevious =  editMenu.addAction("查找上一个(&V)")
        replace =  editMenu.addAction("替换(&R)")
        goTo =editMenu.addAction("转到(&G)")
        editMenu.addSeparator()
        selectAll = editMenu.addAction("全选(&A)")
        self.date_ = editMenu.addAction("时间/日期(&D)")

        # 默认禁用 后面 使用enabledChanged()信号连接
        undo.setEnabled(False)

        # 粘贴 剪切板有东西 可用 
        self.clipbaord_ = QGuiApplication.clipboard()

        undo.setShortcut(QKeySequence.StandardKey.Undo)
        cut.setShortcut(QKeySequence.StandardKey.Cut)
        copy.setShortcut(QKeySequence.StandardKey.Copy)
        self.paste.setShortcut(QKeySequence.StandardKey.Paste)
        delete.setShortcut(QKeySequence.StandardKey.Delete)
        self.find_.setShortcut(QKeySequence.StandardKey.Find)
        self.findNext.setShortcut(QKeySequence.StandardKey.FindNext)
        self.findPrevious.setShortcut(QKeySequence.StandardKey.FindPrevious)
        replace.setShortcut(QKeySequence.StandardKey.Replace)
        goTo.setShortcut("Ctrl+G")
        selectAll.setShortcut(QKeySequence.StandardKey.SelectAll)
        self.date_.setShortcut("F5")

    def setFormatMenu(self):
        """格式菜单项以及菜单
        """
        formatMenu =  self.menuBar_.addMenu("格式(&O)")
        self.lineWrap = formatMenu.addAction("自动换行(&W)")
        self.font_ =  formatMenu.addAction("字体(&F)")

        # 自动换行行为 设置为可勾选并默认为勾选状态  
        ## 设置QAction可勾选 https://doc.qt.io/qtforpython-6.5/PySide6/QtGui/QAction.html#PySide6.QtGui.PySide6.QtGui.QAction.setCheckable
        self.lineWrap.setCheckable(True)
        self.lineWrap.setChecked(True)

    def setViewMenu(self):
        """
        查看菜单 子菜单 子行为以及对应快捷方式
        缩放三个子行为 放大缩小 恢复默认大小
        状态栏可勾选
        """
        viewMenu = self.menuBar_.addMenu("查看(&V)")
        zoomMenu = viewMenu.addMenu("缩放(&Z)")
        zoomIn = zoomMenu.addAction("放大(&I)")
        zoomOut = zoomMenu.addAction("缩小(&O)")
        zoomBack = zoomMenu.addAction("恢复默认缩放")
        self.showStatusBar_ =  viewMenu.addAction("状态栏(&S)")

        zoomIn.setShortcut(QKeySequence.StandardKey.ZoomIn)
        zoomOut.setShortcut(QKeySequence.StandardKey.ZoomOut)
        zoomBack.setShortcut("Ctrl+0")

        self.showStatusBar_.setCheckable(True)
        self.showStatusBar_.setChecked(True)

    def setHelpMenu(self):
        """
        帮助菜单 
        查看帮助 github/gitee 文档
        发送反馈 提交Issue
        关于即使本 QShowMessage
        """
        helpMenuBar = self.menuBar_.addMenu("帮助(&H)")
        self.helpWebInfo = helpMenuBar.addAction("查看帮助(&H)")
        helpMenuBar.addAction("发送反馈(&F)")
        helpMenuBar.addSeparator()
        self.aboutNotePad = helpMenuBar.addAction("关于记事本(&A)")

    def setPlainText(self):
        """嵌入行文本编辑器 并设置右键菜单
        """
        centerWidget = QWidget(self)
        self.setCentralWidget(centerWidget)
        self.plainTextEdit = QPlainTextEdit(centerWidget)
        vbox= QVBoxLayout()        
        vbox.addWidget(self.plainTextEdit)
        ## 默认情况下 左上右下 都为11 QVBoxLayout 父类 QLayout模块的setContentsMargins方法
        # 设置盒子边距 https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QLayout.html#PySide6.QtWidgets.QLayout.setContentsMargins
        vbox.setContentsMargins(0,0,0,0)
        centerWidget.setLayout(vbox)

        # 设置右键菜单
        # rightMenu  = QMenu(self.plainTextEdit)
        # rightMenu.addAction("撤销(&U)")
        # rightMenu.addSeparator()
        # rightMenu.addAction("剪切(&T)")
        # rightMenu.addAction("复制()")
        
        contentMenu =  self.plainTextEdit.createStandardContextMenu()

        ## QPlainTextEdit 的父类 QFrame模块中的setFrameShape()和setFrameShadow 方法
        # 继承关系 https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QPlainTextEdit.html#PySide6.QtWidgets.QPlainTextEdit
        self.plainTextEdit.setFrameShape(QFrame.Shape.NoFrame)
        # self.plainTextEdit.setFrameShadow(QFrame.Shadow.Plain)
        
    def setMyStatusBar(self):
        """放入状态栏
            不手动换行行数不会更新
            使用QMainWindow的类会导致 多次实例化QLable()并显示到状态栏中
        """
        # 设置默认状态栏 然后 添加标签 通过方法 更新 文本
        self.statusBar_ = self.statusBar()
        self.upDownLable = QLabel("                                                                   ")
        self.textCursorLable = QLabel("第 行，第 列")
        self.statusBar_.addWidget(self.upDownLable)
        self.statusBar_.addWidget(self.textCursorLable)

    def updateTextCursor(self):
        """更新文本光标位置
        """
        textCursor = self.plainTextEdit.textCursor()
        self.textCursorLable.setText(f"第{textCursor.blockNumber()+1}行，第{textCursor.columnNumber()+1}列")       

    def eventHand(self):
        self.setEventBind()

    def setEventBind(self):
        """设置事件绑定
        """
        # 文件菜单
        self.newFile_.triggered.connect(self.newFile)
        self.newWindow_.triggered.connect(self.newWindow)
        self.openFile_.triggered.connect(self.openFile)
        self.saveFile_.triggered.connect(self.saveFile)
        self.saveFileAs_.triggered.connect(self.saveFileAs)
        self.printFile.triggered.connect(self.getPrintDialog)
        self.exit_.toggled.connect(self.close)

        # 编辑菜单
        self.clipbaord_.dataChanged.connect(self.updateMenuStatus)
        self.find_.triggered.connect(self.getFindTextDialog)
        self.findNext.triggered.connect(self.getNextTextCursor)
        self.findPrevious.triggered.connect(self.getFindTextDialog)
        self.search.triggered.connect(self.deskSearch)
        self.date_.triggered.connect(self.insertDateTime)
        self.plainTextEdit.cursorPositionChanged.connect(self.updateTextCursor)



        self.lineWrap.triggered.connect(self.setLineWarpMode)
        self.font_.triggered.connect(self.getFontDialog)

        self.showStatusBar_.toggled.connect(self.statusBar_.setVisible)
        self.helpWebInfo.triggered.connect(self.getHelp)
        self.aboutNotePad.triggered.connect(self.getAboutNote)     

    def newFile(self):
        """新建
        """
        self.plainTextEdit.clear()
        self.setWindowTitle("无标题-记事本")
        self.filePath = None

    def newWindow(self):
        """新窗口
        """
        self.notePad = MainNotePad()
        self.notePad.show()

    def openFile(self):
        """打开文件对话框 读取文件 并写入PlainText中
        """
        self.filePath, _ = QFileDialog.getOpenFileName(self, "Open file",self.homePath,"(*.txt);;(*.*)")
        if self.filePath:
            with open(self.filePath,"r") as file:
                self.plainTextEdit.setPlainText(file.read())

            fileName = self.filePath.split("/")[-1]
            titleName = fileName.split(".")[0]
            self.setWindowTitle(f"{titleName} - 记事本")

    def saveFile(self):
        if self.filePath:
            with open(self.filePath,"w") as file:
                file.write(self.plainTextEdit.toPlainText())
        else:
            self.filePath = self.saveFileAs()

    def saveFileAs(self):
        """另存文件为

        :return: 文件路径
        """
        filePath,_ = QFileDialog.getSaveFileName(self,"保存文件",self.homePath,"(*.txt)")
        
        if filePath:
            with open(filePath,"w") as file:
                file.write(self.plainTextEdit.toPlainText())
        return filePath

    def getPrintDialog(self):
        """_summary_
        """
        printer = QPrinter()
        dialog = QPrintDialog(printer).open()
        if dialog.exec():
            self.plainTextEdit.print_(printer)
    
    def getFontDialog(self):
        """获取字体对话框
        """
        ok, font = QFontDialog.getFont()
        if font:
            self.plainTextEdit.setFont(font)
    
    def getFindTextDialog(self):
        """获取查找文本对话框
        """
        findTextDialog = QFindTextDialog(self.plainTextEdit,self.upDownLable ,self)
        findTextDialog.show()
        self.lineEditText = findTextDialog.findLineEdit.text()
        return findTextDialog
    
    def getNextTextCursor(self):
        """获取下一个文本光标
            与QFindDialog 中相关代码的关系 重构？

        """
        findStr = self.lineEditText
        if findStr:
            self.plainTextEdit.find(findStr)
    
    def deskSearch(self):
        searchStr =  self.plainTextEdit.textCursor().selectedText()
        url = f"https://cn.bing.com/search?q={searchStr}"
        QDesktopServices.openUrl(url)

    def insertDateTime(self):
        """插入日期时间
        """
        currentDateTime = QDateTime.currentDateTime()
        formattedTime = currentDateTime.toString("hh:mm yyyy/MM/dd")
        self.plainTextEdit.insertPlainText(formattedTime)

    def setLineWarpMode(self,checked: bool):
        """是否设置为自动换行

        :param checked: 这是一个二进制的值 用于检测自动换行是否被勾选
        """
        if checked:
            self.plainTextEdit.setLineWrapMode(QPlainTextEdit.LineWrapMode.WidgetWidth)
        else:
            self.plainTextEdit.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)

    def updateMenuStatus(self):
        clipboardText = self.clipbaord_.text()
        if clipboardText:
            self.paste.setEnabled(True)
        else:
            self.paste.setEnabled(False)

    def getHelp(self):
        """获取帮助
        """
        url = "https://gitee.com/BasterHapy/note-pad/tree/develop/"
        QDesktopServices.openUrl(url)

    def getAboutNote(self):
        content = "使用PySide6实现的win10记事本\n作者：开心-开心急了"
        icon = QPixmap("./Images/notePad.jpg")
        aboutNotepad = QMessageBox()
        aboutNotepad.setIconPixmap(icon)
        aboutNotepad.setWindowTitle("关于记事本")
        aboutNotepad.setText(content)
        aboutNotepad.setStandardButtons(QMessageBox.StandardButton.Ok)
        aboutNotepad.exec()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    notepad = MainNotePad()
    notepad.show()
    sys.exit(app.exec())